<?php


require_once(dirname(__FILE__).'/../../common/log.php');
require_once(dirname(__FILE__).'/../../common/defines.php');
require_once(dirname(__FILE__).'/../../common/return.php');
require_once(dirname(__FILE__).'/../../database/mysql.class.php');
require_once(dirname(__FILE__).'/../../database/redis.class.php');

require_once(dirname(__FILE__).'/common.php');


$body  = file_get_contents('php://input');
logd("recv: ".$body);

$data  = json_decode($body, true);
if ((!isset($data['time'])) || (!isset($data['kefuId'])))
{
    loge("params error: ".$body);

    failure(ERR_PARAM);
}

$kefuId  = $data['kefuId'];
$lock    = "server:kefuLock:$kefuId";

//连接数据库
$mysql  = new mysqldb();
$ret    = $mysql->open_db(['dbname' => 'love-hole']);
if ($ret === FAILURE)
{
    failure(ERR_SYSTEM);
}

$redis  = new RedisUtils();
$redis->select(7);
$redis->zrem("server:online", $kefuId);

//对当前客服加互斥锁
$ret  = $redis->lock($lock);
if ($ret === FAILURE)
{
    loge("lock $lock failed !");
}

//获取该客服未回复的用户
$users  = $mysql->select('kefu_message_info', 'senderId', "(recverId = $kefuId) AND (status = 0) GROUP BY senderId");
foreach ($users as $user)
{
    //为用户重新分配新客服
    $userId    = $user['senderId'];
    //删除该用户的分配关系
    $redis->hdel("server:current", $userId);

    do
    {
        $recverId  = get_current_kefu($redis, $userId);
        if ($recverId == USERID_SERVER)
        {
            break;
        }

        //检查新客服是否在线（因为有可能刚分配成功，该客服就离线了）
        //尝试获取新客服的互斥锁。这里必须先对新客服加锁（加锁成功与否都无法唯一判断新客服是否在线，所以不对加锁结果进行判断），否则新客服在线状态可能不准确。
        //例如，假设已获取到的客服A此时刚好离线，则可能存在以下情况：
        //如果不加锁，假设下面zscore之后客服A才被客服离线线程zrem掉(并把数据库中客服A未回复的消息转发给其他客服)，那么当前线程并不知道客服A实际已离线，会继续将当前消息发送给客服A，造成当前消息无人处理。
        //如果先加锁，假设当前线程先锁住，客服离线线程会等待本线程把当前消息写入数据库；假设当前线程后锁住，那么下面zscore就会正确判断出客服A已离线
        //获取互斥锁失败表示：1、新客服正处于离线中（因为客服离线的时候会加锁）；2、正在为新客服分配另一个用户的消息
        //获取互斥锁成功表示：1、新客服在线；2、新客服刚离线完成，刚释放离线锁
        $newLock  = "server:kefuLock:$recverId";
        $redis->try_lock($newLock);
        //通过获取客服分数判断新客服是否在线
        //获取失败：新客服已离线，需要重新为当前用户分配客服
        //获取成功：新客服在线，正常继续流程
        $ret  = $redis->zscore("server:online", $recverId);
        if (empty($ret))
        {
            //重新为当前用户分配客服
            $redis->hdel("server:current", $userId);
            $redis->unlock($newLock);
        }
    } while (empty($ret));

    if ($recverId == USERID_SERVER)
    {
        //未分配到客服时，将用户加入待分配列表
        $redis->rpush("server:waiting", $userId);

        continue;
    }

    //获取该用户未被当前客服回复的消息
    $msgs  = $mysql->select('kefu_message_info', '*', "(senderId = $userId) AND (recverId = $kefuId) AND (status = 0)");
    foreach ($msgs as $msg)
    {
        send_kmsg_message($userId, [(int)$recverId], $msg['type'], 0, json_decode($msg['content']), 1, $msg['umid'], $msg['createTime']);
    }

    if (!empty($msgs))
    {
        //将当前客服未回复的消息的接收者更改为新分配的客服
        $ret  = $mysql->update('kefu_message_info', ['recverId' => $recverId], "(senderId = $userId) AND (recverId = $kefuId) AND (status = 0)");
        if (($ret === FAILURE) || ($ret != count($msgs)))
        {
            loge("update kefu_message_info failed: ".json_encode(['userId' => $userId, 'oldkefu' => $kefuId, 'newkefu' => $recverId]));
        }

        //增加新客服的分数
        $redis->zincrby("server:online", $ret, $recverId);
    }
}

//对当前客服解锁
$ret  = $redis->unlock($lock);
if ($ret === FAILURE)
{
    loge("unlock $lock failed !");
}

success();
